﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
using System.Data;

namespace GestionCegep.Objects
{
    public class Enseignant : PersistentObject
    {
        private static Enseignant oldEnseignant = new Enseignant();

        // Différentes requetes a la base de donnees pour la gestion des enseignants
        private const string selectQuery = "SELECT NUMERO_EMPLOYE, NOM, PRENOM, TELEPHONE, ID_DEPARTEMENT FROM ENSEIGNANT";
        private const string lockQuery = "LOCK TABLE ENSEIGNANT IN EXCLUSIVE MODE";
        private const string insertQuery = "INSERT INTO ENSEIGNANT(NOM) VALUES('{0}') RETURNING NUMERO_EMPLOYE INTO :myOutputParameter";
        private const string updateQuery = "UPDATE ENSEIGNANT SET NOM = '{1}', PRENOM = '{2}', TELEPHONE = '{3}', ID_DEPARTEMENT = {4} WHERE NUMERO_EMPLOYE = {0}";
        private const string deleteQuery = "DELETE FROM ENSEIGNANT WHERE NUMERO_EMPLOYE = {0}";

        private int numeroEmploye;        // Numéro de l'enseignant (Numero sequentiel)
        private string nom;               // Nom de l'enseignant
        private string prenom;            // Prenom de l'enseignant
        private string telephone;         // Numero de telephone de l'enseignant
        private Departement departement;  // Departement de l'enseignant

        // Constructeur
        private Enseignant(int numeroEmploye, string nom, string prenom, string telephone, Departement departement, bool isNew = false)
        {
            this.numeroEmploye = numeroEmploye;
            this.nom = nom;
            this.prenom = prenom;
            this.telephone = telephone;
            this.departement = departement;
        }

        public Enseignant()
        {
            isNew = true;
        }

        public Enseignant(int numeroEmploye, string nom, string prenom, string telephone, Departement departement)
        {
            this.numeroEmploye = numeroEmploye;
            this.nom = nom;
            this.prenom = prenom;
            this.telephone = telephone;
            this.departement = departement;
            isNew = true;
        }

        public int NumeroEmploye { get { return numeroEmploye; } }
        public string Nom { get { return nom; } set { nom = value; isModified = true; } }
        public string Prenom { get { return prenom; } set { prenom = value; isModified = true; } }
        public string NomComplet { get { return nom + ", " + prenom; } }
        public string Telephone { get { return telephone; } set { telephone = value; isModified = true; } }
        public Departement Departement { get { return departement; } set { departement = value; isModified = true; } }

        // Insertion d'un enseignants dans la base de données
        public override void InsertIntoDataBase(OracleConnection OracleConnection, DataStore dataStore)
        {
            OracleDecimal ora_dec;
            OracleCommand command; // Commande Oracle
            string departementId = departement != null ? departement.Id.ToString() : string.Empty;
            try
            {
                command = OracleConnection.CreateCommand(); // Creation de la commande
                command.CommandText = lockQuery; // Verouillage de la table
                command.ExecuteNonQuery();

                command.CommandText = String.Format(insertQuery, nom);
                command.Parameters.Add("myOutputParameter", OracleDbType.Decimal, ParameterDirection.ReturnValue);
                command.ExecuteNonQuery();

                // Recuperation du dernier numero d'employe inserer dans la base de donnees
                ora_dec = (OracleDecimal)command.Parameters["myOutputParameter"].Value;
                numeroEmploye = ora_dec.ToInt32();

                // Journalisation de la transaction
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Defaire, String.Format(deleteQuery, numeroEmploye));
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Refaire, String.Format(insertQuery, nom));

                dataStore.CurrentTransaction.Commit(); // Confirmation de la transaction
                dataStore.Enseignants.Add(this); // Ajout de l'enseignant a la liste des enseignants
            }
            catch (OracleException exception)
            {
                throw exception;
            }
        }

        // Vérouillage pour la mise a jour
        public override void LockForUpdate(OracleConnection OracleConnection)
        {
            try
            {
                OracleCommand command = OracleConnection.CreateCommand(); // Creation de la commande
                command.CommandText = selectQuery + " WHERE NUMERO_EMPLOYE = '" + numeroEmploye + "' FOR UPDATE"; // Vérouillage pour la mise a jour
                command.ExecuteScalar();
                oldEnseignant.numeroEmploye = numeroEmploye;
                oldEnseignant.nom = nom;
                oldEnseignant.prenom = prenom;
                oldEnseignant.telephone = telephone;
                oldEnseignant.departement = departement;
            }
            catch (OracleException exception)
            {
                throw exception;
            }
        }

        // Mise a jour dans la base de donnees
        public override void UpdateIntoDataBase(MyOracleTransaction currentTransaction)
        {
            string departementId = departement != null ? departement.Id.ToString() : "NULL";
            try
            {
                OracleCommand command = currentTransaction.Connection.CreateCommand(); // Creation de la commande Oracle
                command.CommandText = String.Format(updateQuery, numeroEmploye, nom, prenom, telephone, departementId);
                command.ExecuteNonQuery(); // Mise a jour dans la base de données

                departementId = oldEnseignant.departement != null ? oldEnseignant.departement.Id.ToString() : "NULL";
                
                // Journalisation de la transaction
                currentTransaction.PushLogToBD(LogActions.Defaire, String.Format(updateQuery, oldEnseignant.numeroEmploye, oldEnseignant.nom, oldEnseignant.prenom, oldEnseignant.telephone, departementId));
                currentTransaction.PushLogToBD(LogActions.Refaire, command.CommandText);

                currentTransaction.Commit(); // Confirmation de la transaction
            }
            catch (OracleException exception)
            {
                nom = oldEnseignant.nom;
                prenom = oldEnseignant.prenom;
                telephone = oldEnseignant.telephone;
                departement = oldEnseignant.departement;
                throw exception;
            }
        }

        // Suppression dans la base de données
        public override void DeleteFromDataBase(OracleConnection OracleConnection, DataStore dataStore)
        {
            string departementId = departement != null ? departement.Id.ToString() : "NULL";
            OracleCommand command;
            try
            {
                command = OracleConnection.CreateCommand(); // Creation de la commande
                command.CommandText = lockQuery; // Verouillage de la table
                command.ExecuteNonQuery();

                command.CommandText = String.Format(deleteQuery, numeroEmploye); // Suppression de l'enseignant
                command.ExecuteNonQuery();

                // Journalisation des modifications
                string insertQuery = "INSERT INTO ENSEIGNANT VALUES('{0}','{1}',{2},{3},{4})";
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Defaire, String.Format(insertQuery, numeroEmploye, nom, prenom, telephone, departementId));
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Refaire, command.CommandText);

                dataStore.CurrentTransaction.Commit(); // Confirmation de la transaction
                dataStore.Enseignants.Remove(this); // Suppression de l'enseignant de la liste des enseignants
            }
            catch (OracleException exception)
            {
                throw exception;
            }
        }

        // Balayage de la table enseignant pour obtenir toutes les informations
        public static List<Enseignant> GetEnseignantsFromDataBase(OracleConnection OracleConnection, List<Departement> departements)
        {
            List<Enseignant> enseignants = new List<Enseignant>(); // Liste des enseignants
            string departementId;
            Departement departement;

            try
            {
                OracleCommand command = OracleConnection.CreateCommand(); // Creation de la commande Oracle
                command.CommandText = "SELECT NUMERO_EMPLOYE, NOM, PRENOM, TELEPHONE, ID_DEPARTEMENT FROM ENSEIGNANT";
                OracleConnection.Open();
                OracleDataReader reader = command.ExecuteReader(); // Execution de la requete select

                // Tant qu'il y a des donnees dans la table Enseignant
                while (reader.Read())
                {
                    departementId = reader["ID_DEPARTEMENT"].ToString();
                    if (!String.IsNullOrEmpty(departementId))
                        departement = departements.First(d => departementId.Equals(d.Id.ToString()));
                    else
                        departement = null;

                    Enseignant enseignant = new Enseignant(Convert.ToInt32(reader["NUMERO_EMPLOYE"].ToString()),
                                                            reader["NOM"].ToString(),
                                                            reader["PRENOM"].ToString(),
                                                            reader["TELEPHONE"].ToString(),
                                                            departement,
                                                            false);
                    enseignants.Add(enseignant); // Ajout de tout les departements a la liste des enseignants
                }
                OracleConnection.Close(); // Fermeture de la connexion
            }
            catch (Exception exception)
            {
                throw exception;
            }

            return enseignants; // On retourne les enseignants pour le remplissable du DataGridView
        }
    }
}
